#include <iostream>

using std::cout;
using std::endl;

struct CM {
    CM() {  cout << "calling CM()..." << endl; }
    CM(const CM&) {  cout << "calling CM(const CM&)..." << endl; }
    CM(CM&&) { cout << "calling CM(CM&&)..." << endl; }
    CM& operator=(const CM&) {  cout << "calling CM::operator=(const CM&)..." << endl; return *this; }
    CM& operator=(CM&&) {  cout << "calling CM::operator=(CM&&)..." << endl; return *this;}
    ~CM() {  cout << "calling ~CM()..." << endl; }
            
};

struct DM : CM {
    DM() { cout << "calling DM()..." << endl; }
    ~DM() {cout << "calling ~DM()..." << endl; }
};

struct C {
    C(): m(CM()), pm(new CM) {  cout << "calling C()..." << endl; }
    C(const C&);
    C(C&&);
    ~C() {  cout << "calling ~C()..." << endl; delete pm; pm = nullptr; }
    CM m;
    CM *pm;
};

C::C(const C &c) {  
    cout << "calling C(const C&)..." << endl; 
    m = c.m; //拷贝赋值
    pm = new CM(*c.pm); //拷贝构造
}

C::C(C &&c) { 
    cout << "calling C(C&&)..." << endl; 
    m = std::move(c.m); //移动赋值
    pm = c.pm;
    c.pm = nullptr;
}

void f1(C) {
    cout << "calling f1(C)..." << endl; 
}

void f2(C&) {
    cout << "calling f2(C&)..." << endl; 
}

void f3(C&&) {
    cout << "calling f3(C&&)..." << endl; 
}

void f4(const CM &) {
    cout << "calling f4(const CM&)..." << endl; 
}

void f5(CM) {
    cout << "calling f5(CM)..." << endl; 
}


int main() {
    C c1, c2;
    CM cm;
    cout << "Test f1(C)..." << endl;
    cout << "call f1(c1)..." << endl;
    f1(c1); //拷贝c1到栈, 函数返回时新构造的对象自动析构
    cout << "call f1(C())..." << endl;
    f1(C()); //直接构造C, 函数返回自动析构
    cout << "call f1(std::move(c1))..." << endl;
    //移动c1到栈，函数返回时新构造的对象被析构，注意c1成员被移动但自身未被析构
    f1(std::move(c1)); 
    cout << "Test f2(C&)..." << endl;
    cout << "call f2(c2)..." << endl;
    f2(c2); //传c2地址
    cout << "Test f3(C&&)..." << endl;
    cout << "call f3(C())..." << endl;
    f3(C()); //直接构造C后传地址, 函数返回右值被析构
    cout << "call f3(std::move(c2))..." << endl;
    f3(std::move(c2)); //传c2地址，注意c2未被析构 
    cout << "Test f4(const CM&)..." << endl;
    cout << "call f4(cm)..." << endl;
    f4(cm); //传cm地址
    cout << "call f4(CM())..." << endl;
    f4(CM()); //直接构造CM(纯右值), 然后传地址，函数返回自动析构
    cout << "call f4(c2.m)..." << endl;
    f4(c2.m); //左值，传地址
    cout << "call f4(C().m)..." << endl;
    f4(C().m); //xvalue, 传m地址, 函数结束自动析构C
    cout << "call f4(std::move(m))..." << endl;
    f4(std::move(cm)); //xvalue, 传cm地址, 函数结束cm未被析构
    cout << "Test f5(CM)..." << endl;
    cout << "call f5(C().m)..." << endl;
    f5(C().m); //xvalue, m被移动, 函数结束析构移动得到的CM和C
    cout << "call f5(c2.m)..." << endl;
    //xvalue, m被移动, 函数结束析构移动得到的CM, 注意c2未被析构
    f5(std::move(c2.m));
    cout << "call f5(DM())..." << endl;
    //先构造纯右值DM,再将基类CM移动到参数栈，函数返回全部析构
    f5(DM());
    cout << "Finish test!!!" << endl;
    return 0;
}
